<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <title>2FA验证码获取器</title>
  <meta charset="UTF-8">
  <link href="./bootstrap.min.css" rel="stylesheet"> <!--https://cdn.staticfile.net/twitter-bootstrap/5.1.1/css/bootstrap.min.css-->
  <script src="./bootstrap.bundle.min.js"></script> <!--https://cdn.staticfile.net/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js-->
  <script src="./buffer.js"></script>     <!--https://unpkg.com/@otplib/preset-browser@^12.0.0/buffer.js-->
  <script src="./index.js"></script>      <!--https://unpkg.com/@otplib/preset-browser@^12.0.0/index.js-->
</head>
<body>
<div class="text-center">
  <h1 class="m-5">2FA验证码获取器</h1>
  <label for="secretKey" class="form-label">输入你的密钥:</label>
  <input type="text" id="secretKey" placeholder="例如: IKUN...CTRL" class="form-control w-25 d-inline-block">
  <button onclick="generateTOTP()" type="button" class="btn btn-primary">获取验证码</button>
  <!--倒计时：-->
  <div id="countdown"></div>

  <div class="m-2 ">
    <span id="old_2fa" class="btn bg-warning btn-sm bg-opacity-25" data-bs-toggle="tooltip" title="点击复制"></span>
    <span id="2fa" class="btn bg-success btn-sm bg-opacity-25" type="button" data-bs-toggle="tooltip" title="点击复制"></span>
    <span id="next_2fa" class="btn btn-sm bg-primary bg-opacity-25" data-bs-toggle="tooltip" title="点击复制"></span>
  </div>


  <!--清空按钮-->
  <button onclick="clearInput()" class="btn btn-danger btn-sm m-2" style="width: 15%">清空</button>
  <!--提醒可以保存该连接，下次访问就会自动填充密钥-->
  <p id="remind"></p>
</div>


<script>
  let timer;    // 定时器变量

  /**
   * 加载完成网页后 获取url的towFA参数 获取成功并符合规则就自动填入输入框并执行生成TOTP
   *
   * @author Yc
   * @since 2024/4/24 23:38
   */
  window.onload = function () {
    const urlParams = new URLSearchParams(window.location.search);
    const twoFA = urlParams.get('twoFA');
    if (twoFA && /^[A-Z2-7]+=*$/.test(twoFA.toUpperCase())) {
      document.getElementById('secretKey').value = twoFA;
      generateTOTP();
    } else {
      $id('2fa').style.display = 'none';
      $id('old_2fa').style.display = 'none';
      $id('next_2fa').style.display = 'none';
    }
    // 接口输入框的值改变时，清空验证码
    document.getElementById('secretKey').addEventListener('input', clear2faShow);
  };

  /**
   * 生成 TOTP（2FA）
   *
   * @author Yc
   * @since 2024/4/24 23:47
   */
  function generateTOTP() {
    const secret = document.getElementById('secretKey').value;
    if (!secret) return window.alert('请输入密钥');

    try {
      const token = otplib.authenticator.generate(secret);
      copyCode("2fa", token, "当前")

      otplib.authenticator.options = {epoch: new Date().getTime() - 30000};
      const oldToken = otplib.authenticator.generate(secret);
      copyCode("old_2fa", oldToken, "上个")

      otplib.authenticator.options = {epoch: new Date().getTime() + 30000};
      const nextToken = otplib.authenticator.generate(secret)
      copyCode("next_2fa", nextToken, "下个")

      // 把参数添加（或替换）到url
      const urlParams = new URLSearchParams(window.location.search);
      urlParams.set('twoFA', secret);
      window.history.replaceState({}, '', `${window.location.pathname}?${urlParams}`);

      // 提醒可以保存该连接，下次访问就会自动填充密钥
      remind()
      // 停止本来的倒计时
      clearTimeout(timer);
      // 重新启动倒计时
      updateCountdown();
    } catch (_e) {
      window.alert('密钥格式错误');
    }

  }

  /**
   * 动态更新倒计时，每秒更新一次，倒计时结束自动刷新页面，前提是输入了密钥
   *
   * @author Yc
   * @since 2024/4/24 23:43
   */
  function updateCountdown() {
    const countdownElement = $id('countdown');
    // 获取现在时间的秒 当前小于30秒 有效时间=30秒减去当前秒。当前小于60秒 有效时间=60秒减去当前秒
    const now = new Date();
    const currentSeconds = now.getSeconds();
    let countdown; // 倒计时时间（秒）
    if (currentSeconds < 30) countdown = 30 - currentSeconds;
    else countdown = 60 - currentSeconds;

    timer = setInterval(() => {
      if (countdown > 0) {
        countdownElement.innerText = '倒计时: ' + (countdown--) + ' 秒';
      } else {
        countdownElement.innerText = '倒计时结束，自动获取新的 TOTP(2fa)';
        // window.location.reload();
        generateTOTP() // 重新生成TOTP（2fa)
      }
    }, 1000);
  }

  /**
   * 清空输入框的值 停止倒计时 清空显示的2fa
   *
   * @author Yc
   * @since 2024/4/24 23:51
   */
  function clearInput() {
    document.getElementById('secretKey').value = '';
    clear2faShow()
  }

  // 清空显示验证码
  function clear2faShow() {
    clearTimeout(timer);
    $id('countdown').innerText = '';
    $id('2fa').style.display = 'none';
    $id('old_2fa').style.display = 'none';
    $id('next_2fa').style.display = 'none';
    $id('remind').style.display = 'none';
  }

  /**
   * 提示：可以保存该连接，下次访问就会自动填充密钥  点击还能复制URL,点击后文字变成复制成功
   *
   * @author Yc
   * @since 2024/4/25 0:08
   */
  function remind() {
    const remindElement = $id('remind');
    remindElement.style.display = 'block';
    remindElement.innerText = '提示：点击可复制当前链接，下次访问就会自动填充密钥。也可以保存为书签';
    remindElement.style.color = 'blue';
    remindElement.style.fontSize = '16px';
    remindElement.style.fontWeight = 'bold';
    remindElement.style.cursor = 'pointer';
    remindElement.onclick = function () {
      const url = window.location.href;
      navigator.clipboard.writeText(url).then()
      remindElement.innerText = '复制成功';
      remindElement.style.color = 'green';
    }
  }

  /**
   * 复制验证码 等
   *
   * @param id 元素id
   * @param token 验证码
   * @param text 提示文字："上个"|当前|下个
   * @author Yc
   * @since 2024/4/25 1:48
   */
  function copyCode(id, token, text) {
    let elId = $id(id);
    elId.style.display = 'inline';
    elId.innerText = `${text}验证码: ${token}`;
    elId.onclick = () => navigator.clipboard.writeText(token).then(() => {
      elId.innerText = '复制成功: ' + token
      setTimeout(() => {
        generateTOTP()
      }, 2000)
    })
  }


  /**
   * 获取id对应元素
   * @author Yc
   * @since 2024/4/24 23:36
   */
  function $id(id) {
    return document.getElementById(id)
  }

</script>
<script>
  // 初始化提示框
  var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
  var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
    return new bootstrap.Tooltip(tooltipTriggerEl)
  })
</script>
</body>
</html>
